package com.apikey.auth.repository;

import com.apikey.auth.entity.AccessLog;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import java.time.LocalDateTime;
import java.util.List;

/**
 * 访问日志数据访问接口
 * 提供访问日志的数据库操作方法
 *
 * @author API Key Framework
 * @version 1.0
 */
@Repository
public interface AccessLogRepository extends JpaRepository<AccessLog, Long>, JpaSpecificationExecutor<AccessLog> {

    /**
     * 根据时间范围统计访问次数
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return 访问次数
     */
    long countByAccessTimeBetweenAndIsDeletedFalse(LocalDateTime startTime, LocalDateTime endTime);

    /**
     * 根据时间范围统计访问次数（包含已删除记录）
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return 访问次数
     */
    long countByAccessTimeBetween(LocalDateTime startTime, LocalDateTime endTime);

    /**
     * 根据状态码范围和时间范围统计访问次数
     *
     * @param minStatus 最小状态码
     * @param maxStatus 最大状态码
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return 访问次数
     */
    long countByResponseStatusBetweenAndAccessTimeBetweenAndIsDeletedFalse(int minStatus, int maxStatus,
                                                                           LocalDateTime startTime, LocalDateTime endTime);

    /**
     * 根据最小状态码和时间范围统计访问次数
     *
     * @param minStatus 最小状态码
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return 访问次数
     */
    long countByResponseStatusGreaterThanEqualAndAccessTimeBetweenAndIsDeletedFalse(int minStatus,
                                                                                    LocalDateTime startTime, LocalDateTime endTime);

    /**
     * 查询平均响应时间
     *
     * @return 平均响应时间（毫秒）
     */
    @Query("SELECT AVG(al.responseTime) FROM AccessLog al WHERE al.isDeleted = false")
    Double findAverageResponseTime();

    /**
     * 查询指定时间范围内的平均响应时间
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return 平均响应时间（毫秒）
     */
    @Query("SELECT AVG(al.responseTime) FROM AccessLog al WHERE al.isDeleted = false AND al.accessTime BETWEEN :startTime AND :endTime")
    Double findAverageResponseTimeByAccessTimeBetween(@Param("startTime") LocalDateTime startTime, @Param("endTime") LocalDateTime endTime);

    /**
     * 根据时间范围查询状态码分布
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return 状态码分布
     */
    @Query("SELECT a.responseStatus, COUNT(a) FROM AccessLog a WHERE a.accessTime BETWEEN :startTime AND :endTime GROUP BY a.responseStatus ORDER BY COUNT(a) DESC")
    List<Object[]> findStatusDistributionByAccessTimeBetween(@Param("startTime") LocalDateTime startTime,
                                                             @Param("endTime") LocalDateTime endTime);

    /**
     * 根据时间范围查询访问日志列表
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return 访问日志列表
     */
    List<AccessLog> findByAccessTimeBetweenOrderByAccessTimeDesc(LocalDateTime startTime, LocalDateTime endTime);

    /**
     * 删除指定时间之前的访问日志
     *
     * @param cutoffTime 截止时间
     * @return 删除的记录数
     */
    int deleteByAccessTimeBefore(LocalDateTime cutoffTime);

    /**
     * 根据API Key值查询访问日志
     *
     * @param apiKeyValue API Key值
     * @return 访问日志列表
     */
    List<AccessLog> findByApiKeyValueOrderByAccessTimeDesc(String apiKeyValue);

    /**
     * 根据客户端IP查询访问日志
     *
     * @param clientIp 客户端IP
     * @return 访问日志列表
     */
    List<AccessLog> findByClientIpOrderByAccessTimeDesc(String clientIp);

    /**
     * 根据响应状态查询访问日志
     *
     * @param responseStatus 响应状态
     * @return 访问日志列表
     */
    List<AccessLog> findByResponseStatusOrderByAccessTimeDesc(int responseStatus);

    /**
     * 根据API Key值和时间范围统计访问次数
     *
     * @param apiKeyValue API Key值
     * @param startTime   开始时间
     * @param endTime     结束时间
     * @return 访问次数
     */
    long countByApiKeyValueAndAccessTimeBetween(String apiKeyValue, LocalDateTime startTime, LocalDateTime endTime);

    /**
     * 根据客户端IP和删除状态查询访问日志（分页）
     *
     * @param clientIp  客户端IP
     * @param isDeleted 是否删除
     * @param pageable  分页参数
     * @return 分页结果
     */
    Page<AccessLog> findByClientIpAndIsDeletedFalse(String clientIp, Pageable pageable);

    /**
     * 根据响应状态和删除状态查询访问日志（分页）
     *
     * @param responseStatus 响应状态
     * @param isDeleted      是否删除
     * @param pageable       分页参数
     * @return 分页结果
     */
    Page<AccessLog> findByResponseStatusAndIsDeletedFalse(Integer responseStatus, Pageable pageable);

    /**
     * 删除旧的访问日志
     *
     * @param beforeDate 删除此日期之前的日志
     * @return 删除的记录数
     */
    @Modifying
    @Query("UPDATE AccessLog al SET al.isDeleted = true WHERE al.accessTime < :beforeDate")
    int deleteOldLogs(@Param("beforeDate") LocalDateTime beforeDate);

    /**
     * 查询最近的访问日志
     *
     * @param limit 限制数量
     * @return 最近的访问日志列表
     */
    List<AccessLog> findTop10ByIsDeletedOrderByAccessTimeDesc(boolean isDeleted);

    /**
     * 分页查询访问日志
     *
     * @param pageable 分页参数
     * @return 分页结果
     */
    Page<AccessLog> findByIsDeleted(boolean isDeleted, Pageable pageable);

    /**
     * 搜索访问日志
     *
     * @param requestPath 请求路径
     * @param clientIp    客户端IP
     * @param userAgent   用户代理
     * @param pageable    分页参数
     * @return 分页结果
     */
    @Query("SELECT al FROM AccessLog al WHERE al.isDeleted = false AND " +
            "(al.requestPath LIKE CONCAT('%', :requestPath, '%') OR al.clientIp LIKE CONCAT('%', :clientIp, '%') OR al.userAgent LIKE CONCAT('%', :userAgent, '%'))")
    Page<AccessLog> findByRequestPathContainingOrClientIpContainingOrUserAgentContaining(
            @Param("requestPath") String requestPath,
            @Param("clientIp") String clientIp,
            @Param("userAgent") String userAgent,
            Pageable pageable);

    /**
     * 统计成功响应数量
     *
     * @param minStatus 最小状态码
     * @param maxStatus 最大状态码
     * @return 数量
     */
    long countByResponseStatusBetweenAndIsDeletedFalse(int minStatus, int maxStatus);

    /**
     * 查询最近的访问日志
     *
     * @param limit 限制数量
     * @return 访问日志列表
     */
    @Query(value = "SELECT * FROM access_logs ORDER BY access_time DESC LIMIT :limit", nativeQuery = true)
    List<AccessLog> findRecentAccessLogs(@Param("limit") int limit);

    /**
     * 查询热门API Key统计
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @param limit     限制数量
     * @return API Key统计列表
     */
    @Query("SELECT a.apiKeyValue, COUNT(a) as count FROM AccessLog a WHERE a.accessTime BETWEEN :startTime AND :endTime GROUP BY a.apiKeyValue ORDER BY COUNT(a) DESC")
    List<Object[]> findTopApiKeys(@Param("startTime") LocalDateTime startTime, @Param("endTime") LocalDateTime endTime);

    /**
     * 查询热门路径统计
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @param limit     限制数量
     * @return 路径统计列表
     */
    @Query("SELECT a.requestPath, COUNT(a) as count FROM AccessLog a WHERE a.accessTime BETWEEN :startTime AND :endTime GROUP BY a.requestPath ORDER BY COUNT(a) DESC")
    List<Object[]> findTopPaths(@Param("startTime") LocalDateTime startTime, @Param("endTime") LocalDateTime endTime);

    /**
     * 查询热门客户端IP统计
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @param limit     限制数量
     * @return 客户端IP统计列表
     */
    @Query("SELECT a.clientIp, COUNT(a) as count FROM AccessLog a WHERE a.accessTime BETWEEN :startTime AND :endTime GROUP BY a.clientIp ORDER BY COUNT(a) DESC")
    List<Object[]> findTopClientIps(@Param("startTime") LocalDateTime startTime, @Param("endTime") LocalDateTime endTime);

    /**
     * 查询每日统计
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return 每日统计列表
     */
    @Query(value = "SELECT DATE(access_time) as date, COUNT(*) as count FROM access_logs WHERE access_time BETWEEN :startTime AND :endTime GROUP BY DATE(access_time) ORDER BY DATE(access_time)", nativeQuery = true)
    List<Object[]> findDailyStats(@Param("startTime") LocalDateTime startTime, @Param("endTime") LocalDateTime endTime);

    /**
     * 查询每小时统计
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return 每小时统计列表
     */
    @Query(value = "SELECT HOUR(access_time) as hour, COUNT(*) as count FROM access_logs WHERE access_time BETWEEN :startTime AND :endTime GROUP BY HOUR(access_time) ORDER BY HOUR(access_time)", nativeQuery = true)
    List<Object[]> findHourlyStats(@Param("startTime") LocalDateTime startTime, @Param("endTime") LocalDateTime endTime);

    /**
     * 根据API Key ID查询访问日志
     *
     * @param apiKeyId API Key ID
     * @param pageable 分页参数
     * @return 分页结果
     */
    Page<AccessLog> findByApiKeyId(Long apiKeyId, Pageable pageable);

    /**
     * 根据时间范围查询访问日志
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @param pageable  分页参数
     * @return 分页结果
     */
    Page<AccessLog> findByAccessTimeBetween(LocalDateTime startTime, LocalDateTime endTime, Pageable pageable);

    /**
     * 根据API Key ID查询访问日志（未删除）
     *
     * @param apiKeyId API Key ID
     * @param pageable 分页参数
     * @return 分页结果
     */
    Page<AccessLog> findByApiKeyIdAndIsDeleted(Long apiKeyId, boolean isDeleted, Pageable pageable);

    /**
     * 根据时间范围查询访问日志（未删除）
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @param pageable  分页参数
     * @return 分页结果
     */
    Page<AccessLog> findByAccessTimeBetweenAndIsDeleted(LocalDateTime startTime, LocalDateTime endTime, boolean isDeleted, Pageable pageable);
}